#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

#include "common.h"
#include "file_process.h"
#include "list.h"

extern int server_count;
extern struct server *servers[MAX_SERVER];

void rcv_status(char *status_msg)
{
	int i;
	int status[3];
	struct server *sv = NULL;
	int server_id[MAX_SERVER];
	int sid = 0;

	//It's a new node
	if(status_msg[0] == 0)
	{
		for(i=0; i<server_count; i++)
		{
			sv = servers[i];
			send_cmd(sv, sv->min_seq_id, sv->max_rcv_id, 0);
		}
		return ;
	}
	for(i = 0; i < status_msg[0]; i++)
	{
		memcpy(status, status_msg + 1 + i * 3 * sizeof(int), 3*sizeof(int));
		sv = find_server(status[0]);
		if(sv)
		{
			server_id[sid++] = status[0];
			if(sv->min_seq_id < status[1])
				send_cmd(sv, sv->min_seq_id, status[1] - 1, 0);
			if(sv->max_rcv_id > status[2])
				send_cmd(sv, status[2] + 1, sv->max_rcv_id, 1);
		}
	}

	for(i = 0;i < server_count; i++)
	{
		int j;
		struct server *sv = servers[i];
		for(j = 0; j < sid; j++)
			if(sv->server_id == server_id[j])
				break;
		if(j == sid)
		{
			send_cmd(sv, sv->min_seq_id, sv->max_rcv_id, 0);
		}
	}

}

void *recv_flood(void *arg)
{
  struct sockaddr_in my_addr, broadcast_addr;
  int sock_fd;
  char broadcast_ip[IP_LENGTH];

  get_broadcast_ip(broadcast_ip);
  printf("broadcast ip : %s\n", broadcast_ip);

  bzero(&my_addr, sizeof(my_addr));
  my_addr.sin_family = AF_INET;
  my_addr.sin_port = htons(FLOOD_PORT);
  my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  bzero(&broadcast_addr, sizeof(broadcast_addr));
  broadcast_addr.sin_family = AF_INET;
  broadcast_addr.sin_port = htons(FLOOD_PORT);
  broadcast_addr.sin_addr.s_addr = inet_addr(broadcast_ip);

  sock_fd = Socket(AF_INET, SOCK_DGRAM, 0);

  Bind(sock_fd, (struct sockaddr *)&my_addr, sizeof(my_addr));

  while(1)
  {
	struct sockaddr_in addr;
	socklen_t len;
	int bytes;
	struct command cmd;
	char buff[BUF_SIZE];
	bytes = Recvfrom(sock_fd, buff, sizeof(buff), 0, (struct sockaddr*)&addr, &len);
	if(buff[0] == 0x01 && rcv_cmd((struct command*)(buff + 1)) == 0)
	{
		flood(buff, sizeof(struct command) + 1);
		//printf("receive %d from %s \n", bytes, inet_ntoa(addr.sin_addr));
		//printf("receive cmd : %s\n",cmd.cmd);
		print_all_cmd();
	}
	else if(buff[0] == 0x02)
		rcv_status(buff + 1);
  }
}

void *beacon(void *arg)
{
	int i;
	char buff[BUF_SIZE];

	while(1)
	{
		sleep(5);

		buff[0] = 0x02;
		buff[1] = server_count;

		for(i = 0; i < server_count; i++)
		{
			bzero(buff + 2,sizeof(buff)-2);
			memcpy(buff + 2 + i * sizeof(int), &(servers[i]->server_id), sizeof(int));
			memcpy(buff + 2 + (i + 1) * sizeof(int), &(servers[i]->min_seq_id), sizeof(int));
			memcpy(buff + 2 + (i + 2) * sizeof(int), &(servers[i]->max_seq_id), sizeof(int));
		}
		flood(buff, 2 + server_count * 3 * sizeof(int));
		/*
		for (i=0;i<server_count;i++){
			printf("server_id:%d\tmin_seq_id:%d\tmax_rcv_id:%d\n",*(buff+2+i*sizeof(int)),*(buff+2+(i+1)*sizeof(int)),*(buff+2+(i+2)*sizeof(int)));
		}
		*/
	}
}

int main()
{
	pthread_t id;
	pthread_attr_t attr;
	pthread_attr_init (&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	if(pthread_create(&id, &attr, beacon, NULL) != 0)
	{
		printf("recv start error!%s\n", strerror(errno));
		abort();
		exit(1);
	}
	if(pthread_create(&id, &attr, recv_flood, NULL) != 0)
	{
		printf("recv start error!%s\n", strerror(errno));
		abort();
		exit(1);
	}
	while(1)
		sleep(10000);
	
	return 0;
}
